/***************************************************************************************
  *Copyright(C),2010-2016,Sumscope
  *FileName   : TableColumn.cpp
  *Author     : scofined.qi
  *Version    : 1.0
  *Date       : 2016/06/06
  *Desc       : //用于说明此程序文件完成的主要功能
  *Relation   :
  *Other      : //其他内容说明
  *Function   : //主要函数列表，每条记录应包含函数名及功能简要说明
  *History    : //修改历史纪录列表，每条修改记录应包含修改日期，修改者以及修改内容简介
  ***************************************************************************************/
#include "TableColumn.h"
#include "TableCommon.h"
#include <stdarg.h>
#include <core/Utility.h>
#include <core/strings/string_convert.h>

using namespace qb::base;

#ifdef WIN32
#define BASSERT assert
#else
#define _TRUNCATE ((size_t)-1)
#define BASSERT //
#endif

namespace qb{
	namespace ht{

		const char* GetDataTypeName(kDataType type)
		{
			static const char* names[] = {
				"", "date", "float", "double", "bool", "int", "int64", "char", "string", "charptr", "nstring", "time"
			};
			int index = (int)type;
			return (index >= 0 && index < _countof(names)) ? names[index] : names[0];
		}
#define COMP_TYPE(TYPE)  (*(const TYPE*)p1 - *(const TYPE*)p2);
		int CompareDate(const void* p1, const void* p2){
			int f1 = *(const int*)p1;
			int f2 = *(const int*)p2;
			return f1<f2 ? -1 : (f1>f2 ? 1 : 0);
		}
		int CompareBool(const void* p1, const void* p2){
			bool f1 = *(const bool*)p1;
			bool f2 = *(const bool*)p2;
			return f1 == f2 ? 0 : (f1 ? 1 : -1);
		}
		int CompareInt64(const void* p1, const void* p2){
            int64_t f1 = *(const int64_t*)p1;
            int64_t f2 = *(const int64_t*)p2;
			return f1<f2 ? -1 : (f1>f2 ? 1 : 0);
		}
		int CompareChar(const void* p1, const void* p2){
			char f1 = *(const char*)p1;
			char f2 = *(const char*)p2;
			return f1<f2 ? -1 : (f1>f2 ? 1 : 0);
		}
		int CompareFloat(const void* p1, const void* p2){
			float f1 = *(const float*)p1;
			float f2 = *(const float*)p2;
			return f1<f2 ? -1 : (f1>f2 ? 1 : 0);
			//	return d == 0.0f ? 0 : (d < 0.0f ? -1 : 1);
		}
		int CompareDouble(const void* p1, const void* p2){
			double f1 = *(const double*)p1;
			double f2 = *(const double*)p2;
			return f1<f2 ? -1 : (f1>f2 ? 1 : 0);
		}
		int CompareInt(const void* p1, const void* p2){
			int f1 = *(const int*)p1;
			int f2 = *(const int*)p2;
			return f1<f2 ? -1 : (f1>f2 ? 1 : 0);
		}
        int CompareCharArray(const void* p1, const void* p2){
			return strcmp((const char*)p1, (const char*)p2);
		}
        int CompareNString(const void* p1, const void* p2)
		{
			// 对应kDataTypeNString 类型
			//int ret = 0;
			//const unsigned int* pi1 = (const unsigned int*)p1;
			//const unsigned int* pi2 = (const unsigned int*)p2;
			//while (!(ret = *pi1 - *pi2) && *pi2)
			//	++pi1, ++pi2;
			//return ret < 0 ? -1 : (ret>0 ? 1:0);
			//return strcmp((const char*)p1+4, (const char*)p2+4);

			//int ret = 0;
			//const unsigned int* pi1 = (const unsigned int*)p1;
			//const unsigned int* pi2 = (const unsigned int*)p2;
			//unsigned short cap = *((const unsigned short*)p1);
			//unsigned short cap2 = *((const unsigned short*)p2);
			//unsigned short len = *((const unsigned short*)p1 + 1);
			//unsigned short len2 = *((const unsigned short*)p2 + 1);
			////SASSERT(cap == cap2 && len < cap && len2 < cap && cap%4==0);
			//pi1++, pi2++;
			//const unsigned int* end = pi2 + *((const unsigned short*)p1);
			//while (pi2<end && ret==0)
			//{
			//	unsigned int i1 = *(unsigned int *)pi1;
			//	unsigned int i2 = *(unsigned int *)pi2;
			//	ret = i1 - i2;
			//	++pi1, ++pi2;
			//}
			//return ret < 0 ? -1 : (ret>0 ? 1 : 0);
			int ret = 0;
			const unsigned int* pi1 = (const unsigned int*)p1;
			const unsigned int* pi2 = (const unsigned int*)p2;
			const unsigned int* end = (const unsigned int*)p2 + (*((const unsigned short*)p1) / 4);
			do
			{
				++pi1, ++pi2;
			} while (!(ret = *pi1 - *pi2) && pi2 < end);
			return ret < 0 ? -1 : (ret>0 ? 1 : 0);

			//for (unsigned int i = 0; i < len;++i)
			//{
			//	cmp = pi1[i + 1] - pi2[i + 1];
			//	if (cmp != 0)
			//		return cmp;
			//}
			//return 0;
		}
		int CompareCharPtr(const void* p1, const void* p2){
			const char** str1 = (const char**)p1;
			const char** str2 = (const char**)p2;
			if (*str1 && *str2)	return strcmp(*str1, *str2);
			if (*str1 == 0 && *str2 == 0)return 0;
			if (*str1 == 0)return -1;
			return 1;
		}
		int CompareTime(const void* p1, const void* p2){
			time_t t = COMP_TYPE(time_t); return t == (time_t)0 ? 0 : (t < (time_t)0 ? -1 : 1);
		}
		FuncColumnComp GetDefaultCompFunc(kDataType type)
		{
			switch (type)
			{
			case kDataTypeDate:return CompareDate;
			case kDataTypeFloat:return CompareFloat;
			case kDataTypeDouble:return CompareDouble;
			case kDataTypeBool:return CompareBool;
			case kDataTypeInt:return CompareInt;
			case kDataTypeInt64:return CompareInt64;
			case kDataTypeChar:return CompareChar;
			case kDataTypeCharArray:return CompareCharArray;
			case kDataTypeCharPtr:return CompareCharPtr;
			case kDataTypeTime:return CompareTime;
			case kDataTypeNString:return CompareNString;
				break;
			}
			return 0;
		}
		int GetTypeSize(kDataType type, int bytes)
		{
			// 获取某个类型的字节大小，有的是变长的
			switch (type)
			{
			case kDataTypeDate:return sizeof(int);
			case kDataTypeFloat:return sizeof(float);
			case kDataTypeDouble:return sizeof(double);
			case kDataTypeBool:return sizeof(bool);
			case kDataTypeInt:return sizeof(int);
            case kDataTypeInt64:return sizeof(int64_t);
			case kDataTypeChar:return sizeof(char);
			case kDataTypeCharArray:return bytes;
			case kDataTypeNString:return bytes;
			case kDataTypeCharPtr:return sizeof(char*);
			case kDataTypeTime:return sizeof(time_t);
				break;
			}
			return 0;
		}

		TableDesc::TableDesc() :m_keycolumn((kColumn)0), m_flagcolumn((kColumn)(-1))
		{
			m_columns.clear();
		}
		int TableDesc::GetRecordSize()const
		{
			int size = 0;
			if (m_columns.size() > 0)
			{
				int align = 1;
				for (int i = 0; i < (int)m_columns.size(); i++)
				{
					kDataType type = m_columns[i].GetDataType();
					if (type == kDataTypeDouble || type == kDataTypeInt64){ align = 8; break; }
					if (type == kDataTypeInt || kDataTypeDate || kDataTypeFloat || kDataTypeTime)
					{
						align = align < 4 ? 4 : align;
					}
				}
				const ColumnInfo& last = m_columns[m_columns.size() - 1];
				int bytes = last.GetFieldBytes();
				size = last.GetOffset() + bytes;
				size = align == 1 ? size : (ROUND_ALIGN(size, align));
			}
			return size;
		}
		void TableDesc::AddColumn(const char* field, const char* name, kDataType type, kColFormatType format,
			int offset, int bytes, FuncColumnComp comp /*= 0*/, kUnitType unit /*= kColFormatTypeNone*/)
		{
			bytes = GetTypeSize(type, bytes);
			//if (offset <= 0)
			//{
			//	if (m_columns.size() > 0)
			//	{
			//		ColumnInfo& last = m_columns.at(m_columns.size() - 1);
			//		offset = last.GetOffset() + last.GetFieldBytes();
			//	}
			//	else
			//		offset = 0;
			//}

            BASSERT(field && name);
            BASSERT(bytes >= 1 && offset >= 0);

			if (comp == 0)
				comp = GetDefaultCompFunc(type);

            BASSERT(comp);
            ColumnInfo ci;
            FIELDCOPY(ci.m_field,field);
            FIELDCOPY(ci.m_name,name);
#ifdef WIN32
            wcsncpy_s(ci.m_fieldw, sizeof(tFieldNameW), G2W(ci.m_field, strlen(ci.m_field)).c_str(), _TRUNCATE);
#else
            wcscpy(ci.m_fieldw, G2W(ci.m_field, strlen(ci.m_field)).c_str());
#endif
			ci.m_namelen = strlen(ci.m_name);
			ci.m_data_type = type;
			ci.m_unit_type = unit;
			ci.m_format = format;
			ci.m_bytes = bytes;
			ci.m_offset = offset;
			ci.m_id = (kColumn)m_columns.size();
			ci.m_comp = comp;
			ci.m_dec = false;


			if (m_columns.size() > 0)
			{
				ColumnInfo& last = m_columns.at(m_columns.size() - 1);
				//SASSERT(last.GetOffset()+last.GetFieldBytes()==ci.GetOffset());
			}
			m_columns.push_back(ci);




			////////////////////////////////////////////////////////////////////////////////////////////////////
		}



        StatUtil::StatUtil(const char* name, unsigned long reportgap, int* capture) :m_gap(reportgap),
			m_sum(0.0), m_lasteach(0.0), m_count(0), m_capture(capture)
		{
			FIELDCOPY(m_name, name);
			memset(m_message, 0, 256);
			m_capture_sum = m_capture_start = 0;
		}

		void StatUtil::Start(const char* message)
		{
			FIELDCOPY(m_message, message);
			m_message[255] = 0;
			if (m_capture)
				m_capture_start = *m_capture;
        //	m_start = HighResTime();
		}

		void StatUtil::End()
		{
        /*	m_sum += m_start.elapsed();
			m_count++;
			m_capture_sum += m_capture ? (*m_capture - m_capture_start) : 0;
			if (GetTickCount() - m_last >= m_gap)
			{
				m_last = GetTickCount();
				double each = m_sum / m_count;
				double increase = (each - m_lasteach)*100.0 / m_lasteach;

				m_lasteach = each;
				BVIEW(0, 0, 0, "[STATUTIL] [name]=%s [message]=%s sum:%.6f count:%d each:%.6f each increase:%.6f%%  capture:%.4f",
					m_name, m_message,
					m_sum, m_count, each, increase,
					m_capture ? (m_capture_sum*1.0 / m_count) : 0.0
					);
            }*/
		}

		StatUtilHelper::StatUtilHelper(StatUtil& util, const char* format, ...) :m_util(&util)
		{
			const size_t tsize = 256;
			char buf[tsize] = { 0 };
			va_list args;
			int ret;
			va_start(args, format);
#ifdef WIN32
            ret = vsprintf_s(buf, tsize, format, args);
#else
            ret = vsprintf(buf, format, args);
#endif
			va_end(args);
			m_util->Start(buf);

		}
	}//namespace ht
}//namespace qb
